package com.geor.gcv.core.mat;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Properties;

import org.nutz.lang.Lang;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import org.slf4j.Logger;

import com.geor.common.log.Loggers;
import com.geor.gcv.core.model.Area;

/**
 * 切分叠加矩形区域
 * 
 * @author geor.yuli
 *
 */
public class RectChipperImpl implements CellChipper {

	static Logger log = Loggers.get();
	// ImageWindow imageWindow = new ImageWindow();

	// public RectChipperImpl() {
	// imageWindow.show();
	// }

	@Override
	public List<Area> execute(Mat mat) throws Exception {
		return chipY(mat);
	}

	/**
	 * X轴投影方式
	 * 
	 * @param mat
	 * @return
	 */
	@SuppressWarnings("unused")
	private List<Area> chipX(Mat mat) {
		// 膨胀
		Mat block = new Mat();
		Mat element = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(40, 3));
		Imgproc.morphologyEx(mat, block, Imgproc.MORPH_DILATE, element);
		try {
			// X轴投影
			List<Integer> counter = new ArrayList<Integer>(block.cols());
			// 投影到X轴
			for (int i = 0; i < block.cols(); i++) {
				int num = 0;
				for (int j = 0; j < block.rows(); j++) {
					double[] matD = block.get(j, i);
					// Y坐标与中心线差值
					if (null != matD && matD[0] == 255d) {
						num += (j - block.rows() / 2);
					}
				}
				counter.add(num);
			}
			for (int i = 0; i < counter.size(); i++) {
				log.trace(String.format("%d: %d", i, counter.get(i)));
				if (counter.get(i) < -5) {
					return Lang.list(new Area(i, 0, mat.cols() - i + 1, mat.rows()));
				}
			}
			return null;

		} finally {
			Mats.releseMat(block, element);
		}
	}

	/**
	 * Y轴投影方式
	 * 
	 * @param mat
	 * @return
	 */
	private List<Area> chipY(Mat mat) {
		// 膨胀
		Mat block = new Mat();
		Mat element = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(40, 3));

		try {
			Imgproc.morphologyEx(mat, block, Imgproc.MORPH_DILATE, element);

			List<Integer> xbounds = new ArrayList<Integer>();
			// 从左侧开始水平向右寻找障碍
			for (int i = 0; i < block.rows(); i++) {
				for (int j = 0; j < block.cols(); j++) {
					double[] matD = block.get(i, j);
					if (null != matD && matD[0] == 255d) {
						log.trace(String.format("[%d, %d]", j, i));
						xbounds.add(j);
						break;
					}
				}
			}

			// 连续n行x>0则取这些中的最小值 （避免误判）
			List<Integer> xboundsOut = new ArrayList<Integer>();
			int HEIGHT = 5;
			// 连续深度
			int height = 0;
			// 上一行bound值
			int prev = 0;

			for (int i = 0; i < xbounds.size(); i++) {
				int xbound = xbounds.get(i);
				// 连续变化
				if (i > 0 && xbound > 0 && Math.abs(xbound - prev) < 3) {
					height++;
				} else {
					height = 0;
				}
				prev = xbound;
				if (height >= HEIGHT) {
					xboundsOut.add(xbound);
				}
			}

			Collections.sort(xboundsOut, new Comparator<Integer>() {
				@Override
				public int compare(Integer o1, Integer o2) {
					return o1.intValue() - o2.intValue();
				}
			});
			if (!Lang.isEmpty(xboundsOut)) {
				// 增加膨胀修正值
				return Lang.list(new Area(xboundsOut.get(0) + 15, 0, 0, 0));
			}
			return null;
		} finally {
			Mats.releseMat(block, element);
		}
	}

	@Override
	public void setParams(Properties properties) {

	}

}
